<?php
/*
  +----------------------------------------------------------------------+
  | PHP Version 5                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2004 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.0 of the PHP license,       |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_0.txt.                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author:  Harun Yayli <harunyayli at gmail.com>                       |
  +----------------------------------------------------------------------+
  +----------------------------------------------------------------------+
  | copy code:  hqlulu <hqlulu at gmail.com>   2010-1-6                |
  +----------------------------------------------------------------------+
*/

//
// don't cache this page
//
header("Cache-Control: no-store, no-cache, must-revalidate");  // HTTP/1.1
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");                                    // HTTP/1.0
set_time_limit(300);

/////////////////////////////////  Confirm  //////////////////////////

if( !isset($_POST['confirm']) ){
echo <<<EOF
<form id="form1" name="form1" method="post" action="">
<input type="hidden" name="confirm" value="1">
<table border="0" align="center" cellpadding="5" cellspacing="1" bgcolor="#666666">
  <tr>
    <td height="35" align="center" bgcolor="#E4E4E4">Memcached Copy</td>
    </tr>
  <tr>
    <td align="center" bgcolor="#FFFFFF"><strong>From</strong>
      <input name="master" type="text" size="20" /> 
    To 
      <input name="slave" type="text" size="20" /></td>
    </tr>
  <tr>
    <td bgcolor="#FFFFFF"><input id="btn" type="submit" name="Submit" value=" -- Start Copy -- " /></td>
    </tr>
  <tr>
    <td bgcolor="#FFFFFF">my site: <a href="http://www.aslibra.com" target="_blank">http://www.aslibra.com</a><br />
      <br />
      format: IP[:Port] (192.168.1.5:11211) </td>
  </tr>
</table>
</form>
EOF;
	exit;
}else{

	//set master and slave
	$MEMCACHE_SERVERS_MASTER = $_POST['master'];
	$MEMCACHE_SERVERS_SLAVE = $_POST['slave'];

	$MEMCACHE_SERVERS[] = $MEMCACHE_SERVERS_MASTER;

}

/////////////////////////////////  Master copy to Slave  //////////////////////////

//连接Slave memcache
$slave = new Memcache;
$strs = explode(':',$MEMCACHE_SERVERS_SLAVE);
$host = $strs[0];
$port = $strs[1] ? $strs[1] : 11211;
$slave->connect($host, $port) or die ("Could not connect Slave: ".$MEMCACHE_SERVERS_SLAVE);

echo '<h1>Start Copy to Slave:</h1>';

$m=0;
$cacheItems= getCacheItems();
$items = $cacheItems['items'];

foreach($items as $server => $entries) {

	//连接Master memcache
	$master = new Memcache;
	$strs = explode(':',$server);
	$host = $strs[0];
	$port = $strs[1] ? $strs[1] : 11211;
	$master->connect($host, $port) or die ("Could not connect Master: ".$MEMCACHE_SERVERS_MASTER);

	foreach($entries as $slabId => $slab) {
		//每个entry
		echo '<hr>slabId:'.$slabId;
		$i=0;
		$items = dumpCacheSlab($server,$slabId,$slab['number']);
		foreach($items['ITEM'] as $itemKey=>$itemInfo){
			//echo $itemKey.' ';
			$i ++;
			//复制内容
			$slave->set($itemKey,$master->get($itemKey));
		}
		echo " ITEM_NUM: ".$i;
		$m += $i;
	}
}

echo "<hr> TOTAL_ITEM_COUNT: ".$m;


/////////// MEMCACHE FUNCTIONS /////////////////////////////////////////////////////////////////////

function sendMemcacheCommands($command){
    global $MEMCACHE_SERVERS;
	$result = array();

	foreach($MEMCACHE_SERVERS as $server){
		$strs = explode(':',$server);
		$host = $strs[0];
		$port = $strs[1];
		$result[$server] = sendMemcacheCommand($host,$port,$command);
	}
	return $result;
}
function sendMemcacheCommand($server,$port,$command){

	$s = @fsockopen($server,$port);
	if (!$s){
		die("Cant connect to:".$server.':'.$port);
	}

	fwrite($s, $command."\r\n");

	$buf='';
	while ((!feof($s))) {
		$buf .= fgets($s, 256);
		if (strpos($buf,"END\r\n")!==false){ // stat says end
		    break;
		}
		if (strpos($buf,"DELETED\r\n")!==false || strpos($buf,"NOT_FOUND\r\n")!==false){ // delete says these
		    break;
		}
	}
    fclose($s);
    return parseMemcacheResults($buf);
}
function parseMemcacheResults($str){

	$res = array();
	$lines = explode("\r\n",$str);
	$cnt = count($lines);
	for($i=0; $i< $cnt; $i++){
	    $line = $lines[$i];
		$l = explode(' ',$line,3);
		if (count($l)==3){
			$res[$l[0]][$l[1]]=$l[2];
			if ($l[0]=='VALUE'){ // next line is the value
			    $res[$l[0]][$l[1]] = array();
			    list ($flag,$size)=explode(' ',$l[2]);
			    $res[$l[0]][$l[1]]['stat']=array('flag'=>$flag,'size'=>$size);
			    $res[$l[0]][$l[1]]['value']=$lines[++$i];
			}
		}elseif($line=='DELETED' || $line=='NOT_FOUND'){
		    return $line;
		}
	}
	return $res;

}
function dumpCacheSlab($server,$slabId,$limit){
    list($host,$port) = explode(':',$server);
    $resp = sendMemcacheCommand($host,$port,'stats cachedump '.$slabId.' '.$limit);

   return $resp;

}
function getCacheItems(){
 $items = sendMemcacheCommands('stats items');
 $serverItems = array();
 $totalItems = array();
 foreach ($items as $server=>$itemlist){
    $serverItems[$server] = array();
    $totalItems[$server]=0;
    if (!isset($itemlist['STAT'])){
        continue;
    }

    $iteminfo = $itemlist['STAT'];

    foreach($iteminfo as $keyinfo=>$value){
        if (preg_match('/items\:(\d+?)\:(.+?)$/',$keyinfo,$matches)){
            $serverItems[$server][$matches[1]][$matches[2]] = $value;
            if ($matches[2]=='number'){
                $totalItems[$server] +=$value;
            }
        }
    }
 }
 return array('items'=>$serverItems,'counts'=>$totalItems);
}

?>